package org.ala.tiktools.tools;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 反射相关帮助类
 *
 * @author ala
 * @date 2025-04-04 10:32
 */
public class ReflectionTools {


    /**
     *  反射new
     */
    public static <T> T newInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     *  拿类的泛型类型
     */
    @SuppressWarnings("unchecked")
	public static <T> Class<T> getActualType(Class<?> clazz, int idx) {
        Class<?> superClass = clazz.getSuperclass();
        Type genericSuperClass = superClass.getGenericSuperclass();
        Assert.assertTrue(genericSuperClass instanceof ParameterizedType, String.format("类不含有泛型 class:%s", clazz.getSimpleName()));

        ParameterizedType rt = (ParameterizedType) genericSuperClass;
        Type[] ts = rt.getActualTypeArguments();
        Assert.assertTrue(ts != null, String.format("泛型类型不存在 class:%s", clazz.getSimpleName()));
        Assert.assertTrue(idx >= 0 && idx < ts.length, String.format("idx必须在泛型类型的数量范围内 class:%s, idx:%d, actualCount:%s", clazz.getSimpleName(), idx, ts.length));
        return (Class<T>) ts[idx];
    }


    /**
     *  取本类，父类，实现接口中含有指定注解的方法
     */
    @SuppressWarnings("unchecked")
	public static List<AnnotationMethod> methodByAnnotations(Class<?> clazz, Class<? extends Annotation>... annotations) {
        return methodByAnnotations(clazz, Arrays.stream(annotations).collect(Collectors.toSet()));
    }
    public static List<AnnotationMethod> methodByAnnotations(Class<?> clazz, Set<Class<? extends Annotation>> annotations) {
        //  找到本类中含有annotations注解的方法
        List<AnnotationMethod> list = new ArrayList<>();
        _methodByAnnotations(clazz, annotations, list);
        return list;
    }
    static void _methodByAnnotations(Class<?> clazz, Set<Class<? extends Annotation>> annotations, List<AnnotationMethod> list) {
        //  解析本类
        _classMethodByAnnotations(clazz, annotations, list);

        //  解析父类
        Class<?> superClass = clazz.getSuperclass();
        if (superClass != null) {
            _classMethodByAnnotations(superClass, annotations, list);
        }

        //  解析接口
        Class<?>[] infs = clazz.getInterfaces();
        for (Class<?> inf : infs) {
            _classMethodByAnnotations(inf, annotations, list);
        }
    }
    static void _classMethodByAnnotations(Class<?> clazz, Set<Class<? extends Annotation>> annotations, List<AnnotationMethod> list) {
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            Annotation[] annos =  method.getAnnotations();
            for (Annotation anno : annos) {
                if (annotations.contains(anno.annotationType())) {
                    list.add(new AnnotationMethod(anno, method));
                }
            }
        }
    }
    public static class AnnotationMethod {
        protected Annotation annotation;
        protected Method method;

        public AnnotationMethod(Annotation annotation, Method method) {
            this.annotation = annotation;
            this.method = method;
        }

        public Annotation getAnnotation() {
            return annotation;
        }

        public void setAnnotation(Annotation annotation) {
            this.annotation = annotation;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }
    }
}
